
from scrapy_plus.conf import settings

if settings.IS_DISTRIBUTE:
    # 分布式 --queue
    from scrapy_plus.utils.queue import Queue
else:
    # 非分布式
    # six 第三方库 适配 2 , 3
    from six.moves.queue import Queue

# 调度器 出入队列　发给引擎
from scrapy_plus.utils.log import logger
import hashlib
import w3lib.url

from scrapy_plus.utils.set import NormalFilterContainer,RedisFilterContainer

class Scheduler():
    def __init__(self, collector):
        # 让engine 判断完毕 传递调度器
        self.collector = collector

        if settings.IS_DISTRIBUTE:
        # 过滤器容器
            self.filter_container = RedisFilterContainer()
        else:
            self.filter_container = NormalFilterContainer()
        # 初始化队列
        self.queue = Queue()

    # 入队列
    def add_request(self, request):
        # 根据请求对象 生成fp
        fp = self._create_fp(request)

        if request.filter:
            # 过滤
            if not self.filter_request(fp):
                # 不重复 新的请求对象
                self.queue.put(request)
                # 添加到集合
                self.filter_container.add_fp(fp)
            else:
                logger.info('发现重复请求：{}'.format(request.url))
                # self.total_repeat_num += 1
                self.collector.incr(self.collector.repeat_request_nums_key)
        # 不过滤
        else:
            # 不过滤 直接入队列
            self.queue.put(request)
            logger.info('添加重复请求:{}'.format(request.url))

    # 出队列
    def get_request(self):
        try:
            # 队列为空　队列阻塞－－非阻塞
            return self.queue.get(False)
        except:
            return None
    # 去重
    def filter_request(self, fp):
        return self.filter_container.exists(fp)

    # 4.根据request 对象 构建 指纹
    def _create_fp(self, request):

        # 1. url 排序
        url = w3lib.url.canonicalize_url(request.url)

        # 2. method 大小写
        method = request.method.upper()

        # 3. params  data  = {} 排序
        params = sorted(request.params.items())
        data = sorted(request.data.items())

        fp_str = url + method + str(params) + str(data)
        # 4.生成指纹
        fp = hashlib.sha1()
        fp.update(fp_str.encode())
        return fp.hexdigest()